package org.toxsoft.uskat.s5.utils.indexes;

import java.util.HashMap;
import java.util.Map;

import org.toxsoft.core.tslib.utils.errors.*;

/**
 * Индексация доступа к значениям по ключу
 * <p>
 * Индексация реализуется с помощью сортировки ключей элементов при формировании индекса с дальнейшим доступом к
 * элементам через двоичный поиск. Несмотря на схожесть (по представлению данных клиенту: ключ-значение) с картами
 * {@link Map} и их аналогами, индекс картой не является, так как допускает хранение нескольких элементов под одним
 * ключом (при {@link #unique()} == false ) и позволяет определять "ближайшее положение" ключа в индексе даже если ключа
 * в индексе нет.
 * <p>
 * По результатам тестирования определено, что производительность индекса выше (почти в два раза) чем {@link HashMap}
 * при наборах размером до 10000 элементов. При размерах близким к 10000 производительность примерно одинакова. При
 * размерах более 10000 {@link HashMap} выигрывает в производительности в линейной зависимости от размера набора.
 * Высокая производительность индекса в наборах до 10000 элементов объясняется отсутствием необходимости использования
 * boxing для примитивных типов представляющих ключи коллекции.
 *
 * @author mvk
 * @param <K> тип ключа
 * @param <V> тип значения
 */
public interface IIndex<K extends Comparable<K>, V> {

  /**
   * Возвращает признак того, что ключи индекса являются уникальными в индексе
   *
   * @return <b>true</b> ключи являются уникальными <b>false</b>ключи не являются уникальными.
   */
  boolean unique();

  /**
   * Возвращает максимально возможное количество элементов в индексе
   *
   * @return int размер индекса
   */
  int capacity();

  /**
   * Возвращает текущее количество элементов в индексе
   * <p>
   * При создании нового индекса watermark = 0. watermark увеличивается на 1 после каждого добавления пары ключ-значение
   * в индекс. При восстановлении индекса watermark = {@link #capacity()}.
   *
   * @return int текущее количество элементов в индексе
   */
  int watermark();

  /**
   * Проверяет целостность индекса
   *
   * @throws TsIllegalStateRtException нарушение целостности индекса
   */
  void check();

  /**
   * Возвращает ключ в индексе
   * <p>
   * Реализация метода является высокопроизводительной
   *
   * @param aIndex int индекс ключа
   * @return K ключ
   * @throws TsIllegalArgumentRtException неверный индекс ключа
   */
  K key( int aIndex );

  /**
   * Возвращает значение в индексе
   * <p>
   * Реализация метода является высокопроизводительной
   *
   * @param aIndex int индекс значения
   * @return V значение
   * @throws TsIllegalArgumentRtException неверный индекс значения
   */
  V value( int aIndex );

  /**
   * Возвращает индекс ключа. Если ключа нет в индексе, то возвращается ближайший к нему.
   * <p>
   * Для неуникальных индексов ({@link #unique()} == false),при наличии нескольких одинаковых ключей, возвращается
   * наименьший индекс найденного ключа
   *
   * @param aKey K ключ
   * @return int индекс ключа. < 0: пустой индекс
   * @throws TsNullArgumentRtException аргумент = null
   */
  int findIndex( K aKey );

  /**
   * Возвращает индекс ключа.
   * <p>
   * Для неуникальных индексов ({@link #unique()} == false),при наличии нескольких одинаковых ключей, возвращается
   * наименьший индекс найденного ключа
   *
   * @param aKey K ключ
   * @return int индекс ключа
   * @throws TsNullArgumentRtException аргумент = null
   * @throws TsIllegalArgumentRtException ключа нет в индексе
   */
  int getIndex( K aKey );

  /**
   * Возвращает значение по ключу. Если ключа нет в индексе, то возвращается значение ближайшее к нему.
   * <p>
   * Для неуникальных индексов ({@link #unique()} == false),при наличии нескольких одинаковых ключей, возвращается
   * значение по наименьшему индексу найденного ключа
   *
   * @param aKey K ключ
   * @return V значение. null: пустой индекс
   * @throws TsNullArgumentRtException аргумент = null
   */
  V findValue( K aKey );

  /**
   * Возвращает значение по ключу.
   * <p>
   * Для неуникальных индексов ({@link #unique()} == false),при наличии нескольких одинаковых ключей, возвращается
   * значение по наименьшему индексу найденного ключа
   *
   * @param aKey K ключ
   * @return V значение
   * @throws TsNullArgumentRtException аргумент = null
   * @throws TsIllegalArgumentRtException ключа нет в индексе
   */
  V getValue( K aKey );
}
